package com.basker.pisces.domain.property.meta;

import org.springframework.util.StringUtils;

import com.basker.pisces.core.meta.IDataField;
import com.basker.pisces.core.meta.IDataObjectMeta;
import com.basker.pisces.core.meta.annotation.DataField;
import com.basker.pisces.domain.ISupportEntityBuild;
import com.basker.pisces.domain.entity.meta.Entity;
import com.basker.pisces.domain.property.InvalidPropertyValueException;
import com.basker.pisces.domain.value.NumberValue;
import com.basker.pisces.utils.ClassUtils;
import com.basker.pisces.utils.NumberUtils;

public class NumberProperty extends Property<NumberValue> implements ISupportEntityBuild {

    @DataField
    private String numberTypeName;
    private transient Class<? extends Number> numberType;

    public NumberProperty() {
        this.setNumberType(Integer.class);
    }

    @Override
    public void bindField(IDataObjectMeta objectMeta) {
        super.bindField(objectMeta);

        if (this.field instanceof IDataField) {
            Class<?> fieldClass = ((IDataField) this.field).getFieldClass();

            if (Number.class.isAssignableFrom(fieldClass)) {
                @SuppressWarnings("unchecked")
                Class<? extends Number> numberType = (Class<? extends Number>) fieldClass;
                this.setNumberType(numberType);

                return;
            }
        }

        throw new RuntimeException("field:'" + this.field.getName() + "' must be a number class");
    }

    @Override
    public void build(Entity entity) {
        if (this.numberType != null) {
            return;
        }

        if (StringUtils.isEmpty(this.numberTypeName)) {
            this.setNumberType(Integer.class);
        } else {
            @SuppressWarnings("unchecked")
            Class<? extends Number> numberCls = (Class<? extends Number>) ClassUtils.getClass(this.numberTypeName);
            this.setNumberType(numberCls);
        }
    }

    @Override
    public NumberValue createValue(Object rawValue) {
        Number number = NumberUtils.parse(rawValue, this.getNumberType());

        if (number == null) {
            return NumberValue.NULL_NUMBER;
        } else {
            return new NumberValue(number);
        }
    }

    public Class<? extends Number> getNumberType() {
        return numberType;
    }

    public String getNumberTypeName() {
        return numberTypeName;
    }

    public void setNumberType(Class<? extends Number> numberType) {
        this.numberType = numberType;
        this.numberTypeName = numberType.getName();
    }

    public void setNumberTypeName(String numberTypeName) {
        this.numberTypeName = numberTypeName;
    }

    @Override
    public void setValue(Object dataObject, Object inputValue) throws InvalidPropertyValueException {
        Number number = NumberUtils.parse(inputValue, this.getNumberType());
        this.setRawValue(dataObject, number);
    }

}
